package com.the_last.exceptionHandle;

import com.the_last.utils.ResponseCode;
import com.the_last.utils.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class GlobeExceptionHandle {
    
    @ExceptionHandler(Exception.class)
    public Result<String> exceptionHandle(Exception e) {
        String errorId = generateErrorId();
        String requestInfo = getRequestInfo();
        String stackTrace = getStackTrace(e);
        
        log.error("""
                        
                        \r========== 系统异常 ==========
                        \r错误ID: {}
                        \r异常类型: {}
                        \r异常信息: {}
                        \r请求信息: {}
                        \r当前用户: {}
                        \r异常堆栈: {}
                        \r==============================
                        \r""",
                errorId,
                e.getClass().getName(),
                e.getMessage(),
                requestInfo,
                getCurrentUsername(),
                stackTrace
        );
        
        return Result.fail("服务器异常 [错误ID: " + errorId + "]");
    }
    
    /**
     * 捕获SpringSecurity的用户不存在异常
     */
    @ExceptionHandler(InternalAuthenticationServiceException.class)
    public Result<String> InternalAuthenticationServiceExceptionHandle(InternalAuthenticationServiceException e) {
        String errorId = generateErrorId();
        String requestInfo = getRequestInfo();
        
        log.warn("""
                        
                        \r========== 认证异常 ==========
                        \r错误ID: {}
                        \r异常类型: {}
                        \r异常信息: {}
                        \r请求信息: {}
                        \r==============================
                        \r""",
                errorId,
                e.getClass().getSimpleName(),
                e.getMessage(),
                requestInfo
        );
        
        return Result.fail("用户不存在 [错误ID: " + errorId + "]");
    }
    
    //处理请求参数格式错误 @RequestBody上@Valid校验失败后抛出的异常是MethodArgumentNotValidException异常。
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        String errorId = generateErrorId();
        String requestInfo = getRequestInfo();
        List<String> errors = ex.getBindingResult().getFieldErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());
        String errorMessage = String.join(", ", errors);
        
        log.warn("""
                        
                        \r========== 参数校验异常 ==========
                        \r错误ID: {}
                        \r异常类型: {}
                        \r校验错误: {}
                        \r请求信息: {}
                        \r当前用户: {}
                        \r================================
                        \r""",
                errorId,
                ex.getClass().getSimpleName(),
                errorMessage,
                requestInfo,
                getCurrentUsername()
        );
        
        return Result.fail(errorMessage + " [错误ID: " + errorId + "]", 400);
    }
    
    //处理请求参数格式错误 @RequestParam上validate失败后抛出的异常是javax.validation.ConstraintViolationException
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<String> handleConstraintViolationException(ConstraintViolationException ex) {
        String errorId = generateErrorId();
        String requestInfo = getRequestInfo();
        List<String> errors = ex.getConstraintViolations().stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
        String errorMessage = String.join(", ", errors);
        
        log.warn("""
                        
                        \r========== 约束校验异常 ==========
                        \r错误ID: {}
                        \r异常类型: {}
                        \r约束错误: {}
                        \r请求信息: {}
                        \r当前用户: {}
                        \r================================
                        \r""",
                errorId,
                ex.getClass().getSimpleName(),
                errorMessage,
                requestInfo,
                getCurrentUsername()
        );
        
        return Result.fail(errorMessage + " [错误ID: " + errorId + "]", 400);
    }
    
    
    @ExceptionHandler(AccessDeniedException.class)
    public Result<String> handleAccessDenied(AccessDeniedException ex) {
        return Result.fail("没有权限", ResponseCode.STATUS_PERMISSION_DENIED);
    }
    
    private String generateErrorId() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 8);
    }
    
    private String getCurrentUsername() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.isAuthenticated() &&
                    !authentication.getPrincipal().equals("anonymousUser")) {
                return authentication.getName();
            }
            return "匿名用户";
        } catch (Exception e) {
            return "未知用户";
        }
    }
    
    private String getRequestInfo() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                return String.format("URL: %s %s, IP: %s, User-Agent: %s",
                        request.getMethod(),
                        request.getRequestURI(),
                        getClientIpAddress(request),
                        request.getHeader("User-Agent"));
            }
            return "无法获取请求信息";
        } catch (Exception e) {
            return "获取请求信息失败: " + e.getMessage();
        }
    }
    
    private String getClientIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    
    private String getStackTrace(Exception e) {
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            String stackTrace = sw.toString();
            return stackTrace.length() > 2000 ? stackTrace.substring(0, 2000) + "..." : stackTrace;
        } catch (Exception ex) {
            return "获取堆栈信息失败: " + ex.getMessage();
        }
    }
    
}
